/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:assign-tracer
 * Create Time: 2016年1月21日 下午4:53:32
 */
package com.lenovo.lmrp.server.assigntracer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Objects;

import javax.persistence.Entity;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beust.jcommander.JCommander;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Scopes;
import com.lenovo.lmrp.base.ABaseMain;
import com.lenovo.lmrp.base.FileSystemService;
import com.lenovo.lmrp.base.IFileService;
import com.lenovo.lmrp.base.ParamNameDef;
import com.lenovo.lmrp.base.event.EventTopic;
import com.lenovo.lmrp.base.mq.MQTopic;
import com.lenovo.lmrp.server.assigntracer.domain.service.QuerySelector;
import com.lenovo.lmrp.server.assigntracer.domain.service.TicketService;
import com.lenovo.lmrp.server.assigntracer.domain.workflow.IProcessService;
import com.lenovo.lmrp.server.assigntracer.domain.workflow.ProcessSelector;
import com.lenovo.lmrp.server.assigntracer.domain.workflow.ProcessServiceImpl;
import com.lenovo.lmrp.server.assigntracer.events.AppGatewayHandle;
import com.lenovo.lmrp.server.assigntracer.events.ItsmGatewayHandle;
import com.lenovo.lmrp.server.assigntracer.facade.EngineerActionFacadeImpl;
import com.lenovo.lmrp.server.assigntracer.facade.FacadeFactory;
import com.lenovo.lmrp.server.assigntracer.facade.IEngineerActionFacade;
import com.lenovo.lmrp.server.assigntracer.facade.ITicketNotificationFacade;
import com.lenovo.lmrp.server.assigntracer.facade.TicketNotificationFacadeImpl;
import com.lenovo.lmrp.server.assigntracer.repository.ARepositoryFactory;
import com.lenovo.lmrp.server.assigntracer.scheduler.ScanExceptionalTicketTask;
import com.lenovo.lmrp.server.assigntracer.spi.AssignTracerRestServer;
import com.lenovo.lmrp.server.assigntracer.util.cache.AssignTracerCache;
import com.lenovo.lmrp.server.assigntracer.util.grap.GrabFactory;
import com.lenovo.lmrp.server.assigntracer.util.pusher.APushFactory;
import com.lenovo.lmrp.server.assigntracer.util.pusher.SenderUtil;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.HibernateDaoFactory;
import com.lenovo.sdc.framework.mq.AMQClient;
import com.lenovo.sdc.framework.mq.MQFactory;
import com.lenovo.sdc.framework.mq.MQServerParam;
import com.lenovo.sdc.framework.mq.MQServerParam.MQProvider;
import com.lenovo.sdc.framework.scheduler.ScheduleTaskManager;
import com.lenovo.sdc.framework.util.AttributeBean;
import com.lenovo.sdc.framework.util.ClassScanner;

/**
 * 
 * @author songyz
 * @version v1.0
 */
public class AssignTracerMain extends ABaseMain {

	private final static Logger logger = LoggerFactory.getLogger(AssignTracerMain.class);

	public static void main(String[] args) {
		AssignTracerMain server = new AssignTracerMain();
		JCommander commander = server.parseCommand(args);

		try {
			server.initialize();
			logger.info("AssignTracer Server startup");
		} catch (Exception exp) {
			System.out.println("failed to initialize AssignTracer Server because " + exp.getMessage());
			exp.printStackTrace();
			commander.usage();
			System.exit(0);
		}
	}

	@Override
	public void initialize() throws Exception {
		// find assigntracer.properties in path
		// load assigntracer.properties data to create AttributeBean object
		AttributeBean params = loadProperties("assigntracer.properties");
		logger.info("successed to load configuration parameters from assigntracer.properties");

		// initialize DAOFacotry, load hibernateFile configuration file from
		// path
		initializeDAOFactory();
		logger.info("successed to initialized DAOFactory");

	      // initialize activiti engine
        File configFile = getConfigurationFile("activiti.cfg.xml");
        if (configFile.exists() == false)
            throw new FileNotFoundException("not found configuration file " + configFile.getAbsolutePath());
        ProcessEngine engine = ProcessEngineConfiguration
                        .createProcessEngineConfigurationFromInputStream(new FileInputStream(configFile))
                        .buildProcessEngine();
        ProcessServiceImpl psImpl = new ProcessServiceImpl(engine);
        
		// setup cache
		new AssignTracerCache(params);
		logger.info("successed to initialized AssignTracerCache");

		// Grab strategy is initialized
		new GrabFactory(params);
		logger.info("Grab strategy is initialized");

		// initialize RestClientFactory
		new RestClientFactory(params);
        
		// create Guice DI container
		Injector injector = Guice.createInjector(new Module() {

			@Override
			public void configure(Binder binder) {
				// bind tracer Configuration parameter to AttributeBean instance
				binder.bind(AttributeBean.class).toInstance(params);

				// bind IFileService as singleton instance
				binder.bind(IFileService.class).toInstance(new FileSystemService(params));

				binder.bind(TicketService.class);
				binder.bind(QuerySelector.class);
				binder.requestStaticInjection(SenderUtil.class);

				binder.install(new ARepositoryFactory.RepositoryModule());
				binder.install(new APushFactory.PushModule());

				binder.bind(AssignTracerRestServer.class).in(Scopes.SINGLETON);

				 // bind MQClient as singleton instance
                MQServerParam mqparam = new MQServerParam(
                    MQProvider.valueOf(params.getAttribute(ParamNameDef.MQ_SERVER_TYPE, MQProvider.ZEROMQ.name())), 
                    params.getAttribute(ParamNameDef.MQ_SERVER_HOST, "localhost"), 
                    params.getAttribute(ParamNameDef.MQ_SERVER_PORT, ParamNameDef.MQ_DEFAULT_PORT));
                binder.bind(AMQClient.class).toInstance(new MQFactory(mqparam).createMQClient());
				logger.info("MQclient create successed.");

				// 绑定工作流的service
				binder.bind(IProcessService.class).toInstance(psImpl);
				
				// 绑定工作流的查询类
				binder.bind(ProcessSelector.class);
				
                // bind Process Facade
				binder.bind(IEngineerActionFacade.class).to(EngineerActionFacadeImpl.class).in(Scopes.SINGLETON);
				binder.bind(ITicketNotificationFacade.class).to(TicketNotificationFacadeImpl.class).in(Scopes.SINGLETON);
				binder.bind(FacadeFactory.class).toInstance(FacadeFactory.getInstance());
				
                // 绑定 主题处理器
                binder.bind(AppGatewayHandle.class).in(Scopes.SINGLETON);
                binder.bind(ItsmGatewayHandle.class).in(Scopes.SINGLETON);
			}
		});
		logger.info("successed to setup DI Container");
		
		// MQ client subscibe ticket event and appgateway event
		AMQClient client = injector.getInstance(AMQClient.class);
		client.subscribe(MQTopic.APPGWEVENT.name(), injector.getInstance(AppGatewayHandle.class));
		client.subscribe(EventTopic.TICKET_EVENT.name(), injector.getInstance(ItsmGatewayHandle.class));
		logger.info("MQclient successed subscribe topic :{}", MQTopic.APPGWEVENT, MQTopic.ITSMGWEVENT);
		
		//启动定时任务 扫描异常工单
		ScanExceptionalTicketTask exceptionalTicketTask = new ScanExceptionalTicketTask(client, ADaoFactory.getDefault(), params);
		ScheduleTaskManager.getDefaultSchduler().scheduleTask(exceptionalTicketTask);
		
		logger.info("scan exceptional Ticket Task started.");
		// start AssignTracerRestServer, use Guice to inject configuration
		// parameter
		AssignTracerRestServer rs = injector.getInstance(AssignTracerRestServer.class);
		rs.start();
		logger.info("successed to deploy Rest API Service");
	}

	public void initializeDAOFactory() throws Exception {
		File configFile = getConfigurationFile("hibernate.cfg.xml");
		if (configFile.exists() == false)
			throw new FileNotFoundException("not found configuration file " + configFile.getAbsolutePath());

		// create Hibernate configuration object
		Configuration config = new Configuration().configure(configFile);

		// scan package to get PO entity class and add to Hibernate manager
		ClassScanner scanner = new ClassScanner();
		List<Class<?>> classes = scanner.scanning("com.lenovo.lmrp.api.model.entity", true);
		classes.forEach(clz -> {
			if (Objects.nonNull(clz.getAnnotation(Entity.class)))
				config.addAnnotatedClass(clz);
		});

		// create hibernate session factory then create HibernateDaoFactory
		ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(config.getProperties())
				.build();
		SessionFactory sf = config.buildSessionFactory(serviceRegistry);
		ADaoFactory.setDefaultFactory(new HibernateDaoFactory(sf, null, true));
	}
}
